﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Entity;
using System.Web;

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace CorreoSocialWeb.Models
{
    [System.ComponentModel.DataAnnotations.Schema.Table("Usuarios")]
    public class Usuario
    {
        [Key]
        public int Id { get; set; }
        public string Email { get; set; }
        public string NombreDeUsuario { get; set; }
        public int Reputacion { get; set; }

        public double? PosicionActualLatitud { get; set; }
        public double? PosicionActualLongitud { get; set; }
        public DateTime? PosicionFHActualizacion { get; set; }

        [Required]
        public String Apellido { get; set; }
        public Boolean correoConfirmado { get; set; }

        public String UserName { get; set; }

        [Required]
        public String Nombre { get; set; }

        [System.ComponentModel.DataAnnotations.Schema.ForeignKey("Domicilio")]
        public int DomicilioId { get; set; }

        [Association("Domicilio", "DomicilioId", "Id")]
        public Domicilio Domicilio { get; set; }

        public Int32 DNI { get; set; }

        public DateTime FechaNacimiento { get; set; }

        public String NroTelefonoCelular { get; set; }

        public String NroTelefonoFijo { get; set; }

        public String FotoDNI1 { get; set; }
        public String FotoDNI2 { get; set; }
        public String FotoServicio1 { get; set; }
        public String FotoServicio2 { get; set; }

        public Boolean correoEnviado { get; set; }

        [NotMapped]
        public string NombreReputacionString
        {
            get
            {
                var rep = new EnumStringHelper().Get(this.ReputacionEnu);

                return string.Format("{0} ({1})", this.NombreDeUsuario
                    , rep == string.Empty ? "sin rep" : rep
                    );
            }
        }

        public void MandarMailSolicitudRuta(RutaDeEnvio rutaDeEnvio, string urlConfirmacion)
        {
            this.MandarMail("CorreoSocial - Solicitud de Envío"
                , string.Format("Hola, {0}!\n\nEl usuario {1} te pidió que participes del envío \"{2}\" utilizando la ruta \"{3}\".\n\nPara ver más detalles hacé click acá: {4}.{5}"
                , rutaDeEnvio.Ruta.Usuario.NombreDeUsuario
                , rutaDeEnvio.Envio.Usuario.NombreReputacionString
                , rutaDeEnvio.Envio.OrigenDestinoString
                , rutaDeEnvio.Ruta.OrigenDestinoString
                , urlConfirmacion
                , !string.IsNullOrEmpty(rutaDeEnvio.ComentariosSolicitud) ? string.Format("\n\nObservaciones: {0}", rutaDeEnvio.ComentariosSolicitud) : string.Empty)
                );
        }

        public void MandarMailDespachoAMensajero(RutaDeEnvio rutaDeEnvio)
        {
            this.MandarMail("CorreoSocial - Envio Despachado"
                , string.Format("Hola, {0}!\n\nEl usuario {1} indicó que te ha entregado el contenido del envío para que lo lleves a destino.\n\nRecordá que podés utilizar la app Android para indicarle tu posición actual!"
                , rutaDeEnvio.Ruta.Usuario.NombreDeUsuario
                , rutaDeEnvio.Envio.Usuario.NombreReputacionString)
                );
        }

        public void MandarMailCancelacionDeSolicitudRutaAMensajero(RutaDeEnvio rutaDeEnvio)
        {
            this.MandarMail("CorreoSocial - Solicitud de Envío Cancelada"
                , string.Format("Hola, {0}!\n\nEl usuario {1} canceló el pedido para que participes de un envío.\n\nYa no es necesario que respondas el pedido de solicitud anterior."
                , rutaDeEnvio.Ruta.Usuario.NombreDeUsuario
                , rutaDeEnvio.Envio.Usuario.NombreReputacionString)
                );
        }

        public void MandarMailSolicitudRutaRechazada(RutaDeEnvio ruta)
        {
            var mensaje = string.Format("El usuario mensajero {0} rechazó participar de tu envio \"{1}\" utilizando la ruta \"{2}\".\n\nMotivo/Observaciones: {3}"
            , ruta.Mensajero.NombreDeUsuario
            , ruta.Envio.OrigenDestinoString
            , ruta.Ruta.OrigenDestinoString
            , ruta.ComentariosRechazo);

            this.MandarMail("CorreoSocial - Solicitud de Envío Rechazada", mensaje);
        }

        public void MandarMailSolicitudRutaAceptada(RutaDeEnvio ruta)
        {
            var mensaje = string.Format("El usuario mensajero {0} aceptó participar de tu envio \"{1}\", utilizando la ruta \"{2}\".\n\nPonete en contacto con él para coordinar el despacho!\n\n\nDatos de Contacto:{3}"
            , ruta.Mensajero.NombreDeUsuario
            , ruta.Envio.OrigenDestinoString
            , ruta.Ruta.OrigenDestinoString
            , ruta.Mensajero.DatosDeContactoString
            );

            this.MandarMail("CorreoSocial - Solicitud de Envío Aceptada", mensaje);
        }

        public void MandarMailDatosDeContactoRemitente(RutaDeEnvio ruta)
        {
            var mensaje = string.Format("Te enviamos los datos de contacto del usuario remitente {0}, del cual aceptaste participar de su envío \"{1}\" utilizando la ruta \"{2}\".\n\nPonete en contacto con él para coordinar el despacho!\n\n\nDatos de Contacto:{3}"
            , ruta.Remitente.NombreDeUsuario
            , ruta.Envio.OrigenDestinoString
            , ruta.Ruta.OrigenDestinoString
            , ruta.Remitente.DatosDeContactoString
            );

            this.MandarMail("CorreoSocial - Solicitud de Envío Aceptada", mensaje);
        }

        private void MandarMail(string asunto, string mensaje)
        {
            EmailService s = new EmailService();

            s.Enviar(this.Email, asunto, mensaje);
        }

        public void MandarMailConfirmacion(string url)
        {
            var asunto = "Confirmá tu cuenta en CorreoSocial";

            var mensaje = String.Format("Hola, {0}!\n\nPara confirmar tu EMail, en CorreoSocial, ingresá al siguiente link: \n\n{1}\n\n\nTe esperamos!"
                , this.UserName
                , url);

            EmailService s = new EmailService();

            s.Enviar(this.Email, asunto, mensaje);
        }

        public void MandarMailPerfilAprobado(string url)
        {
            var asunto = "Bienvenido a CorreoSocial!";

            var mensaje = String.Format("Hola, {0}!\n\nTu perfil ha sido aprobado, ya podés ingresar en CorreoSocial y comenzar a solicitar envíos o publicar rutas.\n\n\n Ingresá ahora: {1}!"
                , this.UserName
                , url);

            EmailService s = new EmailService();

            s.Enviar(this.Email, asunto, mensaje);
        }

        public void MandarMailPerfilRechazado(string motivo)
        {
            var asunto = "CorreoSocial - Perfil Rechazado";

            var mensaje = String.Format("Hola, {0}!\n\nLamentablemente tu perfil no ha sido aprobado. Si lo deseas, podés volver a intentarlo registrándote nuevamente.\n\n\nEl revisor ha especificado el siguiente motivo de rechazo: {1}."
                , this.UserName
                , motivo);

            EmailService s = new EmailService();

            s.Enviar(this.Email, asunto, mensaje);
        }

        [NotMapped]
        public bool TienePosicion
        {
            get
            {
                return this.PosicionFHActualizacion.HasValue;
            }
        }

        public bool TienePosicionActualizadaA(DateTime fecha)
        {
            if (!this.TienePosicion)
                return false;

            return this.PosicionFHActualizacion >= fecha;
        }

        public void MandarMailEnvioFinalizadoMensajero(RutaDeEnvio ruta)
        {
            string mensaje = string.Format("Hola, {0}.\n\nFinalizaste tu participación en el envío \"{1}\" del usuario {2}, en tu ruta \"{3}\"."
                , this.NombreDeUsuario
                , ruta.Envio.OrigenDestinoString
                , ruta.Remitente.NombreDeUsuario
                , ruta.Ruta.OrigenDestinoString
                );

            this.MandarMail("CorreoSocial - Envío Finalizado", mensaje);
        }

        public void MandarMailEnvioFinalizadoRemitente(RutaDeEnvio ruta)
        {
            string mensaje = string.Format("Hola, {0}.\n\nFinalizaste tu envío \"{1}\" con participación del mensajero {2} (ruta \"{3}\")."
                , this.NombreDeUsuario
                , ruta.Envio.OrigenDestinoString
                , ruta.Mensajero.NombreDeUsuario
                , ruta.Ruta.OrigenDestinoString
                );

            this.MandarMail("CorreoSocial - Envío Finalizado", mensaje);
        }

        public void MandarMailTeCalificaron(Usuario calificador, PuntajeDeCalificacion puntaje)
        {
            string mensaje = string.Format("Hola, {0}.\n\nEl usuario {1} te calificó por la participación en un envío, indicando que esta fue \"{2}\"."
                , this.NombreDeUsuario
                , calificador.NombreDeUsuario
                , new EnumStringHelper().Get(puntaje)
                );

            this.MandarMail("CorreoSocial - Te Calificaron", mensaje);
        }

        [NotMapped]
        public PuntajeDeCalificacion ReputacionEnu
        {
            get
            {
                return (PuntajeDeCalificacion)this.Reputacion;
            }
            set
            {
                this.Reputacion = (int)value;
            }
        }

        [NotMapped]
        public string DatosDeContactoString 
        { 
            get
            {
                var texto = string.Empty;
                
                texto += string.Format("\nNombre y Apellido: {0} {1}", this.Nombre, this.Apellido);
                texto += string.Format("\nEmail            : {0}", this.Email);
                texto += string.Format("\nTel. Celular     : {0}", this.NroTelefonoCelular);
                texto += string.Format("\nTel. Fijo:         {0}", this.NroTelefonoFijo);

                return texto;
            }
        }

        public static bool ValidarInicioDeSesion(string usuarioEmail, string contrasenia, out Usuario usuario, out string error)
        {
            usuario = null;
            error = string.Empty;
            var errorGenerico = "Error al iniciar sesión. Verificá tu Usuario/Email y contraseña.";
            
            usuarioEmail = usuarioEmail.Trim();

            // se supone que no hay usuarios ni emails repetidos, por lo que no busco por status
            var tmpUsuario = Usuario.GetPorNombreDeUsuario(usuarioEmail);

            // Busco por email si no lo encontré por usuario
            if (tmpUsuario == null)
                tmpUsuario = Usuario.GetPorEmail(usuarioEmail);

            // no lo encontré ni por email ni por nombre de usuario
            if (tmpUsuario == null)
            {
                error = errorGenerico; 
                return false;
            }

            var applicationUser = tmpUsuario.GetApplicationUser();

            // verifico la contraseña
            if (!applicationUser.ValidarContraseña(contrasenia))
            {
                error = errorGenerico;
                return false;
            }

            // puso la clave bien, me fijo si está activo
            if (applicationUser.EstadoEnu == EstadoUsuarioEnu.MailSinConfirmar)
            {
                error = "Tu Email no está verificado. Por favor, ingresá a CorreoSocial hacienco clic en el link que te enviamos.";
                return false;
            }

            if (applicationUser.EstadoEnu == EstadoUsuarioEnu.PerfilSinVerificar || applicationUser.EstadoEnu != EstadoUsuarioEnu.PerfilVerificado)
            {
                error = "Tu perfil no está validado todavía. En breve recibirás un email con el resultado de verificación.";
                return false;
            }

            usuario = tmpUsuario;

            return true;
        }

        public static Usuario GetPorEmail(string email)
        { 
            email = email.Trim().ToLower();

            return new CorreoSocialDbContext().Usuarios
                .FirstOrDefault(x => x.Email.ToLower().Equals(email));
        }

        public static Usuario GetPorId(int id)
        {
            return new CorreoSocialDbContext().Usuarios
                .FirstOrDefault(x => x.Id.Equals(id));
        }

        public static Usuario GetPorNombreDeUsuario(string nombreDeUsuario)
        {
            nombreDeUsuario = nombreDeUsuario.Trim();

            return new CorreoSocialDbContext().Usuarios
                .FirstOrDefault(x => x.UserName.ToLower().Equals(nombreDeUsuario));
        }

        public ApplicationUser GetApplicationUser()
        {
            return new CorreoSocialDbContext().Users.FirstOrDefault(x => x.UsuarioId.Equals(this.Id));
        }

        public static List<Usuario> GetParaVerificar(OpcionesDePaginacion opcionesDePaginacion)
        {
            var resultados = new CorreoSocialDbContext()
                .Usuarios
                .Include(x => x.Domicilio)
                .Include(x => x.Domicilio.Partido)
                .Include(x => x.Domicilio.Partido.Provincia)
                .Where(x => x.Estado.Equals((int)EstadoUsuarioEnu.PerfilSinVerificar))
                .OrderBy(x=>x.Id)
                .ToList();

            opcionesDePaginacion.SetTotalCount(resultados.Count());

            return resultados
                .Skip(opcionesDePaginacion.ItemsASaltar)
                .Take(opcionesDePaginacion.ItemsATomar).ToList();
        }

        public static bool ExisteMail(string email)
        {
            return new CorreoSocialDbContext().Usuarios.Any(x => x.Email.ToLower().Equals(email));
        }

        public static bool ExisteNombreDeUsuario(string nombreDeUsuario)
        {
            return new CorreoSocialDbContext().Usuarios.Any(x => x.UserName.ToLower().Equals(nombreDeUsuario));
        }

        public static void AprobarPerfil(int usuarioId, bool mandarMail, bool agregarAGrupoUsuarios, string urlDelSitio)
        {
            var db = new CorreoSocialDbContext();

            var usuario = db.Usuarios
                .Where(x => x.Id.Equals(usuarioId) && x.Estado.Equals((int) EstadoUsuarioEnu.PerfilSinVerificar))
                .FirstOrDefault();

            // esto hay que corregirlo, hay que poner estado de usuario
            usuario.correoEnviado = true;
            usuario.EstadoEnu = EstadoUsuarioEnu.PerfilVerificado;

            if (mandarMail)
                usuario.MandarMailPerfilAprobado(urlDelSitio);

            db.SaveChanges();
        }

        public static void RechazarPerfil(int usuarioId, bool mandarMail, string motivo)
        {
            var db = new CorreoSocialDbContext();

            var usuario = db.Usuarios
                .Where(x => x.Id.Equals(usuarioId) && x.Estado.Equals((int) EstadoUsuarioEnu.PerfilSinVerificar))
                .FirstOrDefault();

            usuario.EstadoEnu = EstadoUsuarioEnu.PerfilRechazado;

            if (mandarMail)
                usuario.MandarMailPerfilRechazado(motivo);

            db.SaveChanges();
        }

        public int Estado { get; set; }

        [NotMapped]
        public EstadoUsuarioEnu EstadoEnu
        {
            get
            {
                return (EstadoUsuarioEnu)this.Estado;
            }
            set
            {
                this.Estado = (int)value;
            }
        }

        public static void ConfirmarMail(string applicationUserId)
        {
            var db = new CorreoSocialDbContext();

            var usuario = db.Users.FirstOrDefault(x=>x.Id.Equals(applicationUserId) && x.Estado.Equals((int) EstadoUsuarioEnu.MailSinConfirmar));

            usuario.Estado = (int) EstadoUsuarioEnu.PerfilSinVerificar;

            db.SaveChanges();
        }
    }
}